//
// Created by zj on 18-7-31.
//

#include "pure_ADCT.h"
#include <stdlib.h>
#include "global.h"
#include "List.h"
#include "flash.h"
#include "Interface.h"

double MinTauRatio=0.1;
double MaxTauRatio=0.9;


void pure_ADCT_Stat_Reset()
{
    //重置相应的周期统计变量
    pure_ADCT_Hit_CWH=0;
    pure_ADCT_Hit_CRH=0;
    pure_ADCT_Hit_DRH=0;
    pure_ADCT_Hit_DWH=0;
    pure_ADCT_Count=1;
    pure_ADCT_cycle_physical_write=0;
    pure_ADCT_cycle_physical_read=0;
    pure_ADCT_cycle_flash_write_delay=0.0;
    pure_ADCT_cycle_flash_read_delay=0.0;
}

//定义自适应的读写缓冲区阈值调整函数,函数返回的是更新后的Tau值
int pure_ADCT_UpdateTau(int lastTau)
{
    int Tau,D_Tau,TempTau,MinTau,MaxTau;//表示脏队列的目标长度
    //四射五入
    double B_CLRU,B_DLRU;//表示各自队列的单位收益
    MinTau=(int)(MinTauRatio*PURE_ADCT_CACHE_MAX_SIZE+0.5);
    MaxTau=(int)(MaxTauRatio*PURE_ADCT_CACHE_MAX_SIZE+0.5);

    D_Tau=PURE_ADCT_CACHE_MAX_SIZE-lastTau;

    //如果从底层得到周期的读写时延
    double ave_flash_read_delay,ave_flash_write_delay;
    if(pure_ADCT_cycle_physical_read==0){
        ave_flash_read_delay=0.0;
    }else{
        ave_flash_read_delay=pure_ADCT_cycle_flash_read_delay/pure_ADCT_cycle_physical_read;
    }
    if(pure_ADCT_cycle_physical_write==0){
        ave_flash_write_delay=0.0;
    }else{
        ave_flash_write_delay=pure_ADCT_cycle_flash_write_delay/pure_ADCT_cycle_physical_write;
    }

    B_CLRU=(pure_ADCT_Hit_CRH*ave_flash_read_delay+pure_ADCT_Hit_CWH*ave_flash_write_delay)/lastTau;
    B_DLRU=(pure_ADCT_Hit_DRH*ave_flash_read_delay+pure_ADCT_Hit_DWH*ave_flash_write_delay)/D_Tau;

    //四舍五入
    TempTau=(int)((B_CLRU/(B_CLRU+B_DLRU)*PURE_ADCT_CACHE_MAX_SIZE)+0.5);
    TempTau=max(TempTau,MinTau);
    TempTau=min(TempTau,MaxTau);
    Tau=TempTau;
//    printf("Temp is %d\n",TempTau);

    //  更新对应的统计回写(flash)
//    int temp_write; //一下用以计算写入放大系数
//    ADCT_BW=pure_ADCT_cycle_physical_write;
//    ADCT_FW=flash_write_num-last_flash_write;
//    last_flash_write=flash_write_num;
    //重置相应的周期统计变量
    pure_ADCT_Stat_Reset();

    return Tau;
}



//初始化相关的变量
int PURE_ADCT_init(int cache_size,int blk_num)
{
    PURE_ADCT_CACHE_MAX_SIZE=cache_size;
//    此处初始化的ratio比例沿用CASA
    PURE_ADCT_Tau=(int)(0.5*PURE_ADCT_CACHE_MAX_SIZE+0.5);
    PURE_ADCT_CLRU_Head=CreateList();
    if(PURE_ADCT_CLRU_Head==NULL){
        fprintf(stderr,"error happaned PURE ADCT Init function\n");
        fprintf(stderr,"malloc for PRUE_ADCT_CLRU_Head failed\n");
        assert(0);
    }
    CLRU_CACHE_SIZE=0;
    PURE_ADCT_DLRU_Head=CreateList();
    if(PURE_ADCT_DLRU_Head==NULL){
        fprintf(stderr,"error happaned in PURE_ADCT_Init function\n");
        fprintf(stderr,"malloc for PURE_ADCT_DLRU_Head failed\n");
        assert(0);
    }
    PURE_ADCT_DLRU_CACHE_SIZE=0;
//    第一读写的延迟是底层的flash的单次读写延迟,之后实时更新
    PURE_ADCT_FLASH_WRITE_DELAY=WRITE_DELAY;
    PURE_ADCT_FLASH_READ_DELAY=READ_DELAY;
    return 0;
}
//结束释放内存


void PURE_ADCT_end()
{
    FreeList(PURE_ADCT_CLRU_Head);
    FreeList(PURE_ADCT_DLRU_Head);
}

//变量缓冲区,返回索引的结果,返回-1未命中,0命中的CLRU,1命中的是DLRU
int PURE_ADCT_Search(int LPN,int operation)
{
    int index=-1;
    pNode Ps=NULL;
    Ps=FindLPNinList(PURE_ADCT_CLRU_Head,LPN);
    if(Ps==NULL){
        Ps=FindLPNinList(PURE_ADCT_DLRU_Head,LPN);
        if(Ps!=NULL){
            //命中的是DLRU
            index=1;
        }
    }else{
//        命中的是CLRU
        index=0;
    }

    if(pure_ADCT_Count==ADCTUpdateCycle){
        PURE_ADCT_Tau=pure_ADCT_UpdateTau(PURE_ADCT_Tau);
    }else {
        pure_ADCT_Count++;
    }

    return index;
}

//命中缓冲区的操作，这里第三个参数变为命中类型使用
int PURE_ADCT_HitCache(int LPN,int operation,int HitIndex)
{
//    区分命中的操作是命中CLRU还是命中DLRU
    pNode Ps=NULL;
//    启用自适应的Tau值调整
    if(HitIndex==-1){
        fprintf(stderr,"error happened in PURE_ADCT_HitCache\n");
        fprintf(stderr,"HitIndex is -1!!\n");
        assert(0);
    }
//    此处按照ＡＤＣＴ的调整机制进行调整
//    Adjust_PURE_ADCT_Tau(HitIndex);
//    命中的移动操作,写命中都是将命中的数据页移动到DLRU队列中
//    根据命中的情况,在对应的队列中找到对应的Ps
    if(HitIndex==0){
        if(operation==0){
            pure_ADCT_Hit_CWH++;
        }else{
            pure_ADCT_Hit_CRH++;
        }

    }else if(HitIndex == 1){
        if(operation==0){
            pure_ADCT_Hit_DWH++;
        }else{
            pure_ADCT_Hit_DRH++;
        }
    }


    if(HitIndex==0){
        Ps=FindLPNinList(PURE_ADCT_CLRU_Head,LPN);
    }else{
        Ps=FindLPNinList(PURE_ADCT_DLRU_Head,LPN);
    }
//错误检测
    if(Ps==NULL){
        fprintf(stderr,"error happened in PURE_ADCT_HitCache\n");
        fprintf(stderr,"Can not find LPN %d in CacheList\n",LPN);
        assert(0);
    }
//              命中操作
    buffer_hit_cnt++;
    if(HitIndex==0){
        //命中的是CLRU但是是写命中,需要移动到DLRU
        if(operation==0){
//            命中统计
            buffer_write_hit++;
            cache_write_num++;
            Ps->isD=1;
//           命中的是CLRU,CLRU长度会减少
            MoveToMRU(PURE_ADCT_DLRU_Head,Ps);
            PURE_ADCT_DLRU_CACHE_SIZE++;
            CLRU_CACHE_SIZE--;
//           做一个长度的检测
            if(PURE_ADCT_DLRU_CACHE_SIZE!=GetListLength(PURE_ADCT_DLRU_Head)||CLRU_CACHE_SIZE!=GetListLength(PURE_ADCT_CLRU_Head)){
                fprintf(stderr,"error happened in CASA_HitCache\n");
                fprintf(stderr,"PURE_ADCT_DLRU_CACHE_SIZE is %d\t DLRU-List size is %d\n",PURE_ADCT_DLRU_CACHE_SIZE,GetListLength(PURE_ADCT_DLRU_Head));
                fprintf(stderr,"CLRU_CACHE_SIZE is %d\t CLRU-List size is %d\n",CLRU_CACHE_SIZE,GetListLength(PURE_ADCT_CLRU_Head));
                assert(0);
            }

        }else{
//            命中的是CLRU，但是命中的是读命中
            buffer_read_hit++;
            cache_read_num++;
//            将命中移动到CLRU的头部
            MoveToMRU(PURE_ADCT_CLRU_Head,Ps);
//             做一个长度的检测
            if(PURE_ADCT_DLRU_CACHE_SIZE!=GetListLength(PURE_ADCT_DLRU_Head)||CLRU_CACHE_SIZE!=GetListLength(PURE_ADCT_CLRU_Head)){
                fprintf(stderr,"error happened in CASA_HitCache\n");
                fprintf(stderr,"PURE_ADCT_DLRU_CACHE_SIZE is %d\t DLRU-List size is %d\n",PURE_ADCT_DLRU_CACHE_SIZE,GetListLength(PURE_ADCT_DLRU_Head));
                fprintf(stderr,"CLRU_CACHE_SIZE is %d\t CLRU-List size is %d\n",CLRU_CACHE_SIZE,GetListLength(PURE_ADCT_CLRU_Head));
                assert(0);
            }
        }

    }else{
//        命中的是DLRU，都移动到DLRU队列的MRU位置
        if(operation==0){
            buffer_write_hit++;
            cache_write_num++;
        }else{
            buffer_read_hit++;
            cache_read_num++;
        }
        MoveToMRU(PURE_ADCT_DLRU_Head,Ps);

    }
//      命中操作，数据页迁移完成

    return 0;

}



//未命中加载新的数据到缓冲区的操作,函数最后加载数据的时延delay
double  PURE_ADCT_AddCacheEntry(int LPN,int operation)
{
    double delay=0.0;
    pNode p_new=NULL;
    p_new=(pNode)malloc(sizeof(Node));

    if(p_new==NULL){
        fprintf(stderr,"error happened in PURE_ADCT_AddCacheEntry:\n");
        fprintf(stderr,"malloc for p_new failed\n");
        assert(0);
    }
    p_new->LPN=LPN;
    buffer_miss_cnt++;
    if(operation==0){
        buffer_write_miss++;
        cache_write_num++;
        p_new->isD=1;
        AddNewToMRU(PURE_ADCT_DLRU_Head,p_new);
        PURE_ADCT_DLRU_CACHE_SIZE++;
//        错误检测
        if(PURE_ADCT_DLRU_CACHE_SIZE!=GetListLength(PURE_ADCT_DLRU_Head)){
            fprintf(stderr,"error happened in PURE_ADCT_AddCacheEntry:\n");
            fprintf(stderr,"PURE_ADCT_DLRU_CACHE_SIZE is %d\t DLRU-List size is %d\n",PURE_ADCT_DLRU_CACHE_SIZE,GetListLength(PURE_ADCT_DLRU_Head));
            assert(0);
        }

    }else{
        buffer_read_miss++;
        cache_read_num++;
        p_new->isD=0;
        AddNewToMRU(PURE_ADCT_CLRU_Head,p_new);
        CLRU_CACHE_SIZE++;
//        错误检测
        if(CLRU_CACHE_SIZE!=GetListLength(PURE_ADCT_CLRU_Head)){
            fprintf(stderr,"error happened in PURE_ADCT_AddCacheEntry:\n");
            fprintf(stderr,"CLRU_CACHE_SIZE is %d\t CLRU-List size is %d\n",CLRU_CACHE_SIZE,GetListLength(PURE_ADCT_CLRU_Head));
            assert(0);
        }
    }
//    从底层读取数据页到缓冲区,更新Tau所需要的读写时延
    PURE_ADCT_FLASH_READ_DELAY=callFsim(LPN*4,4,1);
    delay+=PURE_ADCT_FLASH_READ_DELAY;
    physical_read++;

    return delay;
}

//缓冲区满的时候,删除脏页可能引发新的时延delay
double PURE_ADCT_DelCacheEntry(int ReqLPN,int ReqOperation)
{
    double delay=0.0;
    pNode pVictim=NULL;
    int DelLPN=-1;
    if(CLRU_CACHE_SIZE+PURE_ADCT_DLRU_CACHE_SIZE<PURE_ADCT_CACHE_MAX_SIZE){
//        如果缓冲区没有溢出，则没必要执行置换操作
        return delay;
    }

//    根据Tau值和CLRU的长度选择剔除的队列
    if(CLRU_CACHE_SIZE>=PURE_ADCT_Tau){
//        选择CLRU剔除
//        删除链表的LRU位置的数据页
        DeleteLRU(PURE_ADCT_CLRU_Head,&DelLPN);
        CLRU_CACHE_SIZE--;
//        长度错误检测
        if(CLRU_CACHE_SIZE!=GetListLength(PURE_ADCT_CLRU_Head)){
            fprintf(stderr,"error happened in PURE_ADCT_DelCacheEntry:\n");
            fprintf(stderr,"CLRU_CACHE_SIZE is %d\t CLRU-List size is %d\n",CLRU_CACHE_SIZE,GetListLength(PURE_ADCT_CLRU_Head));
            assert(0);
        }
//        干净页不需要回写
    }else{
//        选择DLRU剔除
        DeleteLRU(PURE_ADCT_DLRU_Head,&DelLPN);
        PURE_ADCT_DLRU_CACHE_SIZE--;
//             长度错误检测
        if(PURE_ADCT_DLRU_CACHE_SIZE!=GetListLength(PURE_ADCT_DLRU_Head)){
            fprintf(stderr,"error happened in PURE_ADCT_DelCacheEntry:\n");
            fprintf(stderr,"PURE_ADCT_DLRU_CACHE_SIZE is %d\t DLRU-List size is %d\n",PURE_ADCT_DLRU_CACHE_SIZE,GetListLength(PURE_ADCT_DLRU_Head));
            assert(0);
        }
//        判断DelLPN是否正常
        if(DelLPN<0){
            fprintf(stderr,"error happened in PURE_ADCT_DelCacheEntry:\n");
            fprintf(stderr,"DelLPN is %d  !!!error \n",DelLPN);
            assert(0);
        }
//        脏页回写
        physical_write++;
        PURE_ADCT_FLASH_WRITE_DELAY=callFsim(DelLPN*4,4,0);
        delay+=PURE_ADCT_FLASH_WRITE_DELAY;
    }


    return delay;
}



struct cache_operation PURE_ADCT_Operation={
        init:   PURE_ADCT_init,
        SearchCache:    PURE_ADCT_Search,
        HitCache:   PURE_ADCT_HitCache,
        AddCacheEntry:  PURE_ADCT_AddCacheEntry,
        DelCacheEntry:  PURE_ADCT_DelCacheEntry,
        end:    PURE_ADCT_end
};

struct cache_operation * PURE_ADCT_op_setup()
{
    return &PURE_ADCT_Operation;
}